/**
 * Copyright (c) 2018, 西安星沙网络科技-版权所有
 *
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.waleychain.exchange.service.impl.wallet;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;

import cn.waleychain.exchange.core.constant.DDIC;
import cn.waleychain.exchange.core.constant.DDIC.WalletChangeStatus;
import cn.waleychain.exchange.core.constant.OperatePaymentRemark;
import cn.waleychain.exchange.core.constant.OperatePaymentType;
import cn.waleychain.exchange.core.entity.PageInfo;
import cn.waleychain.exchange.core.exec.ClientException;
import cn.waleychain.exchange.core.exec.CoinWalletBalanceNotEnoughException;
import cn.waleychain.exchange.core.exec.CoinWalletFreezeNotEnoughException;
import cn.waleychain.exchange.core.exec.CoinWalletOperationException;
import cn.waleychain.exchange.core.logger.LoggerHelper;
import cn.waleychain.exchange.core.result.RetResultCode;
import cn.waleychain.exchange.core.utils.BigDecimalUtils;
import cn.waleychain.exchange.core.utils.PageHelper;
import cn.waleychain.exchange.core.utils.RandomUtils;
import cn.waleychain.exchange.core.utils.SequenceUtils;
import cn.waleychain.exchange.core.vaildate.VaildateHelper;
import cn.waleychain.exchange.dao.CoinWalletChangeMapper;
import cn.waleychain.exchange.dao.CoinWalletMapper;
import cn.waleychain.exchange.dao.UserWalletMapper;
import cn.waleychain.exchange.dao.WalletCollectTaskMapper;
import cn.waleychain.exchange.dao.WalletRechargeMapper;
import cn.waleychain.exchange.dao.WalletWithdrawMapper;
import cn.waleychain.exchange.feign.CoinServiceFeign;
import cn.waleychain.exchange.feign.CommonServiceFeign;
import cn.waleychain.exchange.feign.UserServiceFeign;
import cn.waleychain.exchange.model.CoinInfo;
import cn.waleychain.exchange.model.CoinWallet;
import cn.waleychain.exchange.model.CoinWalletChange;
import cn.waleychain.exchange.model.UserInfo;
import cn.waleychain.exchange.model.UserWallet;
import cn.waleychain.exchange.model.WalletCollectTask;
import cn.waleychain.exchange.model.WalletRecharge;
import cn.waleychain.exchange.model.WalletWithdraw;
import cn.waleychain.exchange.service.impl.BaseServiceImpl;
import cn.waleychain.exchange.service.impl.wallet.entity.TransWithdrawParam;
import cn.waleychain.exchange.service.impl.wallet.utils.DefaultCoinClient;
import cn.waleychain.exchange.service.wallet.CoinWalletService;

@Service
public class CoinWalletServiceImpl extends BaseServiceImpl implements CoinWalletService {

	private static final Logger mLog = LoggerFactory.getLogger(CoinWalletServiceImpl.class);
	
	@Autowired
	private CoinWalletMapper coinWalletMapper;
	
	@Autowired
	private UserServiceFeign userFeign;
	
	@Autowired
	private UserWalletMapper userWalletMapper;
	
	@Autowired
	private CoinServiceFeign coinFeign;
	
	@Autowired
	private WalletWithdrawMapper walletWithdrawMapper;
	
	@Autowired
	private WalletRechargeMapper walletRechargeMapper;
	
	@Autowired
	private CoinWalletChangeMapper coinWalletChangeMapper;
	
	@Autowired
	private CommonServiceFeign commonFeign;
	
	@Autowired
	private WalletServiceImpl walletService;
	
	@Autowired
	private DefaultCoinClient defaultCoinClient;
	
	@Autowired
	private WalletCollectTaskMapper walletCollectTaskMapper;
	
	@Override
	public boolean insertUserCoinWallet(CoinWallet wallet) throws Exception {

		return coinWalletMapper.insertSelective(wallet) > 0;
	}
	
	@Override
	public boolean batchInsertUserCoinWallet(Long coinId) throws Exception {

		List<CoinWallet> walletList = coinWalletMapper.fetchCoinWalletListByCoinId(coinId);
		if (walletList.isEmpty()) {
			CoinWallet wallet = new CoinWallet();
			wallet.setBalance(BigDecimalUtils.genInitValue());
			wallet.setFreeze(BigDecimalUtils.genInitValue());
			wallet.setWithdraw(BigDecimalUtils.genInitValue());
			wallet.setRecharge(BigDecimalUtils.genInitValue());
			wallet.setCoinId(coinId);
			wallet.setStatus(DDIC.CoinWalletStatus.NORMAL.id);
			wallet.setAddress(RandomUtils.genRandomUpperAlphaAndDec(22));
			
			coinWalletMapper.batchInsertCoinWallet(wallet);
		}
		
		return true;
	}

	@Override
	public void refreshAcceptor(final CoinInfo coin) throws Exception {
		ExecutorService exec = Executors.newSingleThreadExecutor();
		exec.submit(new Runnable() {
			public void run() {
				try {
					LoggerHelper.printLogInfo(mLog, "default开始初始化");
					defaultCoinClient.refreshAcceptor(coin);
				} catch (Exception e) {
					LoggerHelper.printLogErrorNotThrows(mLog, e, " 初始化异常" + coin.getName());
				}

			}
		});
	}

	@Override
	public PageInfo<CoinWallet> fetchCoinWalletList(Long userId, 
			Long coinId,
			String mobile,
			String address,
			Integer status,
			Integer orderColumn,
			Integer orderType,
			Integer showCount,
			Integer currentPage) throws Exception {
		
		PageHelper.startPage(currentPage, showCount);
		Page<CoinWallet> page = coinWalletMapper.fetchCoinWalletListByUserId(userId, coinId, mobile, address, status, orderColumn, orderType);
		
		return new PageInfo<>(page);
	}
	
	@Override
	public CoinWallet fetchCoinWalletInfo(Long userId, Long coinId) throws Exception {
	
		return coinWalletMapper.fetchCoinWalletByCoinIdAndUserId(userId, coinId);
	}

	@Override
	@Transactional
	public boolean userWithdrawApply(Long userId, Long coinWalletId, Long userWalletId, BigDecimal amount, String mobileCode, String payPassword) throws Exception {

		// 获取用户信息
		UserInfo user = userFeign.fetchUserInfo(userId);
		VaildateHelper.vaildateBooleanResult(user == null, RetResultCode.E20019, userId);
		
		// 验证验证码
		commonFeign.vaildateSmsCode(user.getMobile(), mobileCode);
		
		// 检查是否设置支付密码
		VaildateHelper.vaildateBooleanResult(DDIC.Boolean.BOOL_TRUE_1.id != user.getIsSetPayPassword(), RetResultCode.E20011);
		// 验证支付密码
		VaildateHelper.vaildateBooleanResult(!payPassword.equals(user.getPayPassword()), RetResultCode.E20017);
		
		// 平台账号钱包
		CoinWallet coinWallet = coinWalletMapper.queryByPrimaryKey(coinWalletId);
		VaildateHelper.vaildateBooleanResult(coinWallet == null, RetResultCode.E40001, coinWalletId);
		
		// 获取钱包币信息
		CoinInfo coin = coinFeign.fetchCoinById(coinWallet.getCoinId());
		VaildateHelper.vaildateBooleanResult(coin == null, RetResultCode.E30003, coinWallet.getCoinId());
		
		// 是否允许提现
		VaildateHelper.vaildateBooleanResult(DDIC.IsAllowWithdraw.IS_ALLOW_WITHDRAW_0.id == coin.getIsAllowWithdraw(), RetResultCode.E11001, "禁止提现");
		
		// 验证数量
		VaildateHelper.vaildateBooleanResult(amount.compareTo(coinWallet.getBalance()) == 1, RetResultCode.E11001, "币的可用数量不足");
		
		// 用户私人钱包
		UserWallet userWallet = userWalletMapper.queryByPrimaryKey(userWalletId);
		VaildateHelper.vaildateEntityIsNull(userWallet, "用户私人钱包不存在");
		
		WalletWithdraw walletWithdraw = new WalletWithdraw();
		walletWithdraw.setIdNo(SequenceUtils.generateDefaultSerialNum());
		walletWithdraw.setAddress(userWallet.getAddress());
		walletWithdraw.setType(DDIC.WalletWithdrawType.WALLET_WITHDRAW_TYPE_1.id);
		walletWithdraw.setCoinWalletId(coinWallet.getCoinWalletId());
		walletWithdraw.setAmount(amount);
		walletWithdraw.setFeeRate(coin.getFeeRate());
		// 计算费率
		BigDecimal fee = amount.multiply(coin.getFeeRate());
		if (fee.compareTo(coin.getMinFee()) == -1) {
			fee = coin.getMinFee();
		}
		walletWithdraw.setFee(fee);
		walletWithdraw.setRealAmount(amount.subtract(fee));
		walletWithdraw.setBlockHeight(coin.getScanBlockHeight());
		walletWithdraw.setCreateTime(new Date());
		walletWithdraw.setModifiedTime(new Date());
		
		CoinWalletChange cwc = new CoinWalletChange();
		cwc.setIdNo(SequenceUtils.generateDefaultSerialNum());
		cwc.setCoinWalletId(coinWalletId);
		cwc.setBizType(DDIC.WalletBizType.WALLET_WITHDRAW.id);
		cwc.setBizTypeId(walletWithdraw.getIdNo());
		cwc.setType(DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id);
		cwc.setStatus(DDIC.WalletChangeStatus.STATUS_30.id);
		cwc.setCreateTime(new Date());
		
		// 冻结用户币
		boolean bool3 = this.walletFreezeAmount(coinWallet.getUserId(), coinWallet.getCoinId(), amount, OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS.getRemark(), walletWithdraw.getIdNo());
		
		boolean bool1 = walletWithdrawMapper.insertSelective(walletWithdraw) > 0;
		boolean bool2 = coinWalletChangeMapper.insertSelective(cwc) > 0;
		
		boolean result = bool1 && bool2 && bool3;
		if (result) {
			// 执行转币，通过线程操作
			TransWithdrawParam param = new TransWithdrawParam();
			param.setAddr(userWallet.getAddress());
			param.setAmount(amount);
			param.setChangeId(cwc.getIdNo());
			param.setCoinId(coin.getCoinId());
			param.setCoinWalletId(coinWalletId);
			param.setFee(walletWithdraw.getFee());
			param.setOrderId(walletWithdraw.getIdNo());
			param.setUserId(userId);
			param.setWithdrawId(walletWithdraw.getIdNo());
			
			Executors.newSingleThreadExecutor().submit(new WalletServiceImpl.TransOutTask(param, walletService, false));
		}
		
		return result;
	}

	@Override
	@Transactional
	public boolean setWelletWithdrawStatus(Long idNo, Integer status, String remark) throws Exception {

		// 获取提币申请单信息
		WalletWithdraw walletWithdraw = walletWithdrawMapper.fetchWalletWithdrawById(idNo);
		VaildateHelper.vaildateEntityIsNull(walletWithdraw, "提现数据不存在");
		
		CoinWallet coinWallet = coinWalletMapper.queryByPrimaryKey(walletWithdraw.getCoinWalletId());
		this.vaildateCoinWallet(coinWallet, true);
		
		if (DDIC.WalletChangeStatus.STATUS_30.id == walletWithdraw.getStatus()) {
			
			WalletChangeStatus stat = WalletChangeStatus.convertId(status);
			switch (stat) {
			case STATUS_30:
				// 不做操作
				VaildateHelper.vaildateBooleanResult(true, RetResultCode.E11001, "不允许变更为此状态");
				break;
			case STATUS_31:
				// 审核通过
				
				// 做线程处理
				TransWithdrawParam param = new TransWithdrawParam();
				param.setAddr(walletWithdraw.getAddress());
				param.setAmount(walletWithdraw.getAmount());
				param.setChangeId(walletWithdraw.getWalletChangeId());
				param.setCoinId(coinWallet.getCoinId());
				param.setCoinWalletId(coinWallet.getCoinWalletId());
				param.setFee(walletWithdraw.getFee());
				param.setOrderId(walletWithdraw.getIdNo());
				param.setUserId(coinWallet.getUserId());
				param.setWithdrawId(walletWithdraw.getIdNo());
				
				Executors.newSingleThreadExecutor().submit(new WalletServiceImpl.TransOutTask(param, walletService, true));
				
				return true;
			case STATUS_32:
				// 审核拒绝
				// 1 修改提现状态
				CoinWalletChange cwc = new CoinWalletChange();
				cwc.setIdNo(walletWithdraw.getWalletChangeId());
				cwc.setStatus(DDIC.WalletChangeStatus.STATUS_32.id);
				cwc.setRemark(remark);
				
				// 2 解冻钱包币
				boolean bool1 = this.walletUnfreezeAmount(coinWallet.getUserId(), coinWallet.getCoinId(), walletWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS.getRemark(), 0L);
				boolean bool2 = coinWalletChangeMapper.updateByPrimaryKeySelective(cwc) > 0;
				
				return bool1 && bool2;
			default:
				break;
			}
			
		} else {
			throw new ClientException(RetResultCode.E11001, "非待审核状态不能执行审核操作");
		}
		
		return false;
	}

	@Override
	public boolean walletFreezeAmount(Long userId, Long coinId, BigDecimal freezeAmount, String paymentType, Long orderId) throws Exception {

		// 获取账户
		CoinWallet coinWallet = coinWalletMapper.fetchCoinWalletByCoinIdAndUserId(userId, coinId);
		this.vaildateCoinWallet(coinWallet, true);
		
		if (coinWallet.getBalance().max(freezeAmount) == freezeAmount) {
			throw new CoinWalletBalanceNotEnoughException(RetResultCode.E30007);
		} else {
			// 冻结金额
			CoinWallet updateWallet = new CoinWallet();
			updateWallet.setCoinWalletId(coinWallet.getCoinWalletId());
			updateWallet.setBalance(coinWallet.getBalance().subtract(freezeAmount));
			updateWallet.setFreeze(coinWallet.getFreeze().add(freezeAmount));
			updateWallet.setModifiedTime(new Date());
			
			boolean bool = coinWalletMapper.updateByPrimaryKeySelective(updateWallet) > 0;
			if (bool) {
				// 插入操作记录
				
				this.createPaymentDetail(coinWallet.getUserId(), coinWallet.getCoinId(), coinWallet.getCoinWalletId(), coinWallet.getCoinWalletId(), orderId,  
						DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, paymentType, freezeAmount, OperatePaymentRemark.FREEZE.getRemark());
				
				return bool;
			}
			
			throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
		}
		
	}

	@Override
	public boolean walletUnfreezeAmount(Long userId, Long coinId, BigDecimal freezeAmount, String paymentType, Long orderId) throws Exception {

		// 获取账户
		CoinWallet coinWallet = coinWalletMapper.fetchCoinWalletByCoinIdAndUserId(userId, coinId);
		this.vaildateCoinWallet(coinWallet, true);
		
		// 冻结资金 < 解冻资金
		// 冻结资金 >= 解冻资金
		if (coinWallet.getFreeze().max(freezeAmount) == freezeAmount) {
			throw new CoinWalletFreezeNotEnoughException(RetResultCode.E30005);
		} else {
			// 解锁账号资金
			CoinWallet updateWallet = new CoinWallet();
			updateWallet.setCoinWalletId(coinWallet.getCoinWalletId());
			updateWallet.setBalance(coinWallet.getBalance().add(freezeAmount));
			updateWallet.setFreeze(coinWallet.getFreeze().subtract(freezeAmount));
			updateWallet.setModifiedTime(new Date());
			
			boolean bool = coinWalletMapper.updateByPrimaryKeySelective(updateWallet) > 0;
			if (bool) {
				// 插入操作记录
				this.createPaymentDetail(coinWallet.getUserId(), coinWallet.getCoinId(), coinWallet.getCoinWalletId(), coinWallet.getCoinWalletId(), orderId,  
						DDIC.TradeDetailType.TRADE_DETAIL_TYPE_INCOME.id, paymentType, freezeAmount, OperatePaymentRemark.UNFREEZE.getRemark());
				
				return bool;
			}
			
			throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
		}
		
	}

	@Override
	public boolean transferAmount(long reduceWalletId, long addWalletId, long coinId, BigDecimal increment, String paymentType, long orderId) throws Exception {

		// 支出账户
		CoinWallet outWallet = coinWalletMapper.queryByPrimaryKey(reduceWalletId);
		// 验证账户
		this.vaildateCoinWallet(outWallet, true);
		if (outWallet.getBalance().max(increment) == increment) {
			throw new CoinWalletBalanceNotEnoughException(RetResultCode.E30007);
		}

		// 扣减账号
		CoinWallet updateWallet = new CoinWallet();
		updateWallet.setCoinWalletId(outWallet.getCoinWalletId());
		updateWallet.setBalance(outWallet.getBalance().subtract(increment));
		updateWallet.setModifiedTime(new Date());
		
		boolean bool = coinWalletMapper.updateByPrimaryKeySelective(updateWallet) > 0;
		if (bool) {
			// 收入账户
			CoinWallet inWallet = coinWalletMapper.queryByPrimaryKey(addWalletId);
			this.vaildateCoinWallet(inWallet, true);
			
			// 增加账户余额
			updateWallet = new CoinWallet();
			updateWallet.setCoinWalletId(inWallet.getCoinWalletId());
			updateWallet.setBalance(inWallet.getBalance().add(increment));
			updateWallet.setModifiedTime(new Date());
			
			bool = coinWalletMapper.updateByPrimaryKeySelective(updateWallet) > 0;
			
			if (bool) {
				// 增加交易详情
				this.createPaymentDetail(outWallet.getUserId(), coinId, reduceWalletId, addWalletId, orderId, DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, 
						paymentType, increment, OperatePaymentRemark.OUT.getRemark());
				this.createPaymentDetail(inWallet.getUserId(), coinId, addWalletId, reduceWalletId, orderId, DDIC.TradeDetailType.TRADE_DETAIL_TYPE_INCOME.id, 
						paymentType, increment, OperatePaymentRemark.IN.getRemark());
				
				return true;
			}
		}
		
		throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
	}

	@Override
	public boolean withdrawalsAmount(long coinWalletId, long coinId, BigDecimal increment, String paymentType) throws Exception {

		// 获取账户
		CoinWallet coinWallet = coinWalletMapper.queryByPrimaryKey(coinWalletId);
		this.vaildateCoinWallet(coinWallet, true);
		
		VaildateHelper.vaildateBooleanResult(coinWallet.getBalance().max(increment) == increment, RetResultCode.E11001, "钱包账号余额不足");
		
		// 扣减账号
		CoinWallet updateWallet = new CoinWallet();
		updateWallet.setCoinWalletId(coinWallet.getCoinWalletId());
		updateWallet.setBalance(coinWallet.getBalance().subtract(increment));
		updateWallet.setModifiedTime(new Date());
		
		boolean bool = coinWalletMapper.updateByPrimaryKeySelective(updateWallet) > 0;
		
		if (bool) {
			this.createPaymentDetail(coinWallet.getUserId(), coinId, coinWallet.getCoinWalletId(), coinWallet.getCoinWalletId(), 0L, DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, 
					paymentType, increment, OperatePaymentRemark.WITHDRAW.getRemark());

			return true;
		}
		
		throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
	}

	@Override
	@Transactional
	public boolean userCancelWithdraw(Long idNo) throws Exception {
		
		WalletWithdraw walletWithdraw = walletWithdrawMapper.queryByPrimaryKey(idNo);
		VaildateHelper.vaildateEntityIsNull(walletWithdraw, "提现记录不存在");
		
		VaildateHelper.vaildateBooleanResult(DDIC.WalletChangeStatus.STATUS_30.id != walletWithdraw.getStatus(), RetResultCode.E11001, "当前状态不允许操作");
		
		// 获取用户钱包的信息
		CoinWallet coinWallet = coinWalletMapper.queryByPrimaryKey(walletWithdraw.getCoinWalletId());
		vaildateCoinWallet(coinWallet, true);
		
		// 1 修改撤销状态
		CoinWalletChange cwc = new CoinWalletChange();
		cwc.setIdNo(walletWithdraw.getWalletChangeId());
		cwc.setStatus(DDIC.WalletChangeStatus.STATUS_33.id);
		
		coinWalletChangeMapper.updateByPrimaryKeySelective(cwc);
		
		// 2 解冻金额
		this.walletUnfreezeAmount(coinWallet.getUserId(), coinWallet.getCoinId(), walletWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS.getRemark(), walletWithdraw.getIdNo());
		
		return true;
	}

	@Override
	@Transactional
	public boolean sendCoinSuccess(Long idNo, String txId) throws Exception {

		WalletWithdraw walletWithdraw = walletWithdrawMapper.queryByPrimaryKey(idNo);
		VaildateHelper.vaildateEntityIsNull(walletWithdraw, "提现记录不存在");
		
		VaildateHelper.vaildateBooleanResult(DDIC.WalletChangeStatus.STATUS_34.id != walletWithdraw.getStatus(), RetResultCode.E11001, "当前状态不允许操作");
		
		// 获取用户钱包的信息
		CoinWallet coinWallet = coinWalletMapper.queryByPrimaryKey(walletWithdraw.getCoinWalletId());
		vaildateCoinWallet(coinWallet, true);
		
		UserInfo user = userFeign.fetchUserInfo(coinWallet.getUserId());
		VaildateHelper.vaildateBooleanResult(user == null, RetResultCode.E20019, coinWallet.getUserId());
		
		// 解冻账号资金
		this.walletUnfreezeAmount(coinWallet.getUserId(), coinWallet.getCoinId(), walletWithdraw.getAmount(), 
				OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS.getRemark(), walletWithdraw.getIdNo());
		
		// 获取平台用户账号
		Long platformUserId = userFeign.fetchAdminUserId();
		CoinWallet adminWallet = coinWalletMapper.fetchCoinWalletByCoinIdAndUserId(platformUserId, coinWallet.getCoinId());
		vaildateCoinWallet(adminWallet, true);
		
		// 扣减用户资金（提现手续费），同时将扣减的资金归到admin账户
		this.transferAmount(coinWallet.getCoinWalletId(), adminWallet.getCoinWalletId(), coinWallet.getCoinId(), walletWithdraw.getFee(), 
				OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS_POUNDAGE.getRemark(), walletWithdraw.getIdNo());
		
		// 用户实际提币到账金额
		BigDecimal realAmount = walletWithdraw.getAmount().subtract(walletWithdraw.getFee());
		// 扣减用户资金
		this.withdrawalsAmount(coinWallet.getCoinWalletId(), coinWallet.getCoinId(), realAmount, OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS_OUT.getRemark());
		
		// 修改交易id
		WalletWithdraw updateWithdraw = new WalletWithdraw();
		updateWithdraw.setIdNo(idNo);
		updateWithdraw.setTxId(txId);
		updateWithdraw.setModifiedTime(new Date());
		
		walletWithdrawMapper.updateByPrimaryKeySelective(walletWithdraw);
		
		// 修改提现状态
		CoinWalletChange cwc = new CoinWalletChange();
		cwc.setIdNo(walletWithdraw.getWalletChangeId());
		cwc.setStatus(DDIC.WalletChangeStatus.STATUS_31.id);
		
		coinWalletChangeMapper.updateByPrimaryKeySelective(cwc);
		
		// 发送短信
		
		return true;
	}

	@Override
	@Transactional
	public boolean rechargeAmount(long userId, long coinId, BigDecimal increment, String paymentType) throws Exception {

		CoinWallet coinWallet = coinWalletMapper.fetchCoinWalletByCoinIdAndUserId(userId, coinId);
		vaildateCoinWallet(coinWallet, true);
		
		if (increment == null || increment.doubleValue() <= 0) {
			new ClientException(RetResultCode.E11001, "充值金额有误：" + increment.doubleValue());
		}
		
		WalletRecharge recharge = new WalletRecharge();
		recharge.setIdNo(SequenceUtils.generateDefaultSerialNum());
		recharge.setCoinWalletId(coinWallet.getCoinWalletId());
		recharge.setAddress(coinWallet.getAddress());
		recharge.setAmount(increment);
		recharge.setFee(BigDecimalUtils.genInitValue());
		recharge.setRealAmount(increment);
		recharge.setCreateTime(new Date());
		recharge.setModifiedTime(new Date());

		CoinWalletChange change = new CoinWalletChange();
		change.setCoinWalletId(coinWallet.getCoinWalletId());
		change.setBizType(DDIC.WalletBizType.WALLET_RECHARGE.id);
		change.setBizTypeId(recharge.getIdNo());
		change.setType(DDIC.TradeDetailType.TRADE_DETAIL_TYPE_INCOME.id);
		change.setStatus(DDIC.WalletChangeStatus.RECHARGE_SUSS.id);
		change.setRemark(OperatePaymentRemark.RECHARGE.getRemark());
		change.setCreateTime(new Date());
		
		CoinWallet updateCoinWallet = new CoinWallet();
		updateCoinWallet.setCoinWalletId(coinWallet.getCoinWalletId());
		updateCoinWallet.setBalance(coinWallet.getBalance().add(increment));
		updateCoinWallet.setModifiedTime(new Date());
		
		boolean bool1 = walletRechargeMapper.insertSelective(recharge) > 0;
		boolean bool2 = coinWalletChangeMapper.insertSelective(change) > 0;
		boolean bool3 = coinWalletMapper.updateByPrimaryKeySelective(updateCoinWallet) > 0;
		
		if (bool1 && bool2 && bool3) {
			this.createPaymentDetail(coinWallet.getUserId(), coinWallet.getCoinId(), coinWallet.getCoinWalletId(), coinWallet.getCoinWalletId(), recharge.getIdNo(), DDIC.TradeDetailType.TRADE_DETAIL_TYPE_INCOME.id, 
					paymentType, increment, OperatePaymentRemark.RECHARGE.getRemark());
		}
		
		return bool1 && bool2;
	}
	
	@Override
	public PageInfo<WalletWithdraw> fetchWalletWithdrawPageList(Long coinWalletId, String userName, Integer status, Long coinId, String mobile, Date beginDate, Date endDate, int showCount, int currentPage) throws Exception {

		PageHelper.startPage(currentPage, showCount);
		Page<WalletWithdraw> page = walletWithdrawMapper.fetchWalletWithdrawPageList(coinWalletId, userName, status, coinId, mobile, beginDate, endDate);
		
		return new PageInfo<>(page);
	}

	@Override
	public PageInfo<WalletRecharge> fetchWalletRechargePageList(Long coinWalletId, String userName, Integer status, Long coinId, String mobile, Date beginDate, Date endDate, int showCount, int currentPage) throws Exception {

		PageHelper.startPage(currentPage, showCount);
		Page<WalletRecharge> page = walletRechargeMapper.fetchWalletRechargePageList(coinWalletId, userName, status, coinId, mobile, beginDate, endDate);
		
		return new PageInfo<>(page);
	}

	@Override
	public WalletRecharge fetchWalletRechargeByTxIdAndAddress(String txId, String address) throws Exception {

		return walletRechargeMapper.fetchWalletRechargeByTxIdAndAddress(txId, address);
	}

	@Override
	public boolean createWalletCollectTask(WalletCollectTask task) throws Exception {

		return walletCollectTaskMapper.insertSelective(task) > 0;
	}

	@Override
	public CoinWallet fetchWalletByCoinIdAndAddr(Long coinId, String addr) throws Exception {

		return coinWalletMapper.fetchWalletByCoinIdAndAddr(coinId, addr);
	}

	@Override
	@Transactional
	public boolean addWalletRecharge(WalletRecharge recharge, CoinWalletChange change) throws Exception {

		boolean bool1 = walletRechargeMapper.insertSelective(recharge) > 0;
		boolean bool2 = coinWalletChangeMapper.insertSelective(change) > 0;
		
		return bool1 && bool2;
	}

	@Override
	public boolean freezeAndUnfreezeWallet(Long coinWalletId, Integer status) throws Exception {

		CoinWallet wallet = new CoinWallet();
		wallet.setCoinWalletId(coinWalletId);
		wallet.setStatus(status);
		
		return coinWalletMapper.updateByPrimaryKeySelective(wallet) > 0;
	}

}
